#include "Main.h"

// My header
#include "FileTools.h"

// Fridge
#include "StringHash.h"
#include "SuperTree.h"

// External
#include <io.h>
#include <stdio.h>
#include <Windows.h>
#include <Commdlg.h>
#include <Shlobj.h>

static void FindInternal( SuperTree<FFileInfo>* pxFileList, const char* szPath, const char* szExtension, const bool bRecursive, const FHandle xParent );
static const char* GetExtensionForType( FRIDGE_FILE_TYPES eType );
static const char* GetDirectoryForType( FRIDGE_FILE_TYPES eType );
static const char* GetFilterForType( FRIDGE_FILE_TYPES eType );

void FileTools::Platform_FindFiles ( SuperTree<FFileInfo>* pxFileList, FRIDGE_FILE_TYPES eType, const bool bRecursive )
{
	char szDir[ MAX_PATH ];
	szDir[0] = 0;

	strcpy( szDir, GetDirectoryForType( eType ) );
	strcat( szDir, "/" );

	FindInternal( pxFileList, szDir, GetExtensionForType( eType ), bRecursive, TREE_HANDLE_HEAD );
}

bool FileTools::Platform_SavePrompt( FRIDGE_FILE_TYPES eType, char* szSaveFile )
{
	// NOTE: Microsoft recommend the "Common Item Dialog" but it's a huge ballache

	OPENFILENAME xOpenFileStruct;

	// Initialize OPENFILENAME
	ZeroMemory(&xOpenFileStruct, sizeof(xOpenFileStruct));
	xOpenFileStruct.lStructSize = sizeof(xOpenFileStruct);
	xOpenFileStruct.hwndOwner = NULL;
	xOpenFileStruct.lpstrFile = szSaveFile;
	// Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
	// use the contents of szFile to initialize itself.
	xOpenFileStruct.lpstrFile[0] = '\0';
	xOpenFileStruct.nMaxFile = 256; // should pass in the buffer size really
	xOpenFileStruct.nFilterIndex = 1;
	xOpenFileStruct.lpstrFilter = GetFilterForType( eType );
	xOpenFileStruct.lpstrDefExt = GetExtensionForType( eType );
	xOpenFileStruct.lpstrFileTitle = NULL;
	xOpenFileStruct.nMaxFileTitle = 0;
	xOpenFileStruct.lpstrInitialDir = GetDirectoryForType( eType );
	xOpenFileStruct.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
	
	// Display the Open dialog box. 

	if( GetSaveFileName( &xOpenFileStruct ) == TRUE)
	{
		return true;
	}
	return false;
}

bool FileTools::Platform_OpenPrompt( FRIDGE_FILE_TYPES eType, char* szOpenFile )
{
	// NOTE: Microsoft recommend the "Common Item Dialog" but it's a huge ballache

	OPENFILENAME xOpenFileStruct;

	// Initialize OPENFILENAME
	ZeroMemory(&xOpenFileStruct, sizeof(xOpenFileStruct));
	xOpenFileStruct.lStructSize = sizeof(xOpenFileStruct);
	xOpenFileStruct.hwndOwner = NULL;
	xOpenFileStruct.lpstrFile = szOpenFile;
	// Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
	// use the contents of szFile to initialize itself.
	xOpenFileStruct.lpstrFile[0] = '\0';
	xOpenFileStruct.nMaxFile = 256; // should pass in the buffer size really
	xOpenFileStruct.nFilterIndex = 1;
	xOpenFileStruct.lpstrFilter = GetFilterForType( eType );
	xOpenFileStruct.lpstrFileTitle = NULL;
	xOpenFileStruct.nMaxFileTitle = 0;
	xOpenFileStruct.lpstrInitialDir = GetDirectoryForType( eType );
	xOpenFileStruct.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
	
	// Display the Open dialog box. 

	if( GetOpenFileName( &xOpenFileStruct ) == TRUE)
	{
		return true;
	}
	return false;
}

bool FileTools::Platform_MakeDirectory(char const *szPath )
{
	char szTemp[ MAX_PATH ];
	strncpy( &szTemp[0], szPath, MAX_PATH );
	char* pcChar = &szTemp[0];
	while( *pcChar )
	{
		if( *pcChar == '/' )
		{
			*pcChar = '\\';
		}
		++pcChar;
	}

	return ( SHCreateDirectoryEx( 0, &szTemp[0], 0 ) == ERROR_SUCCESS );
}

bool FileTools::Platform_RenameDirectory( const char* szOldDirectory, const char* szNewDirectory )
{
	return ( MoveFile( szOldDirectory, szNewDirectory ) != 0 );
}

bool FileTools::Platform_RemoveTempDirectory()
{
	// ?
	return false;
}

const char* FileTools::Platform_GetTempDirectoryForType( FRIDGE_TEMP_DIRECTORIES eType)
{
	static char szPath[ MAX_PATH ];

	if( SHGetSpecialFolderPath(0, &szPath[0], CSIDL_LOCAL_APPDATA, true ) )
	{
		switch( eType )
		{
			case FRIDGE_DIR_TEMPORARY_ROOT:
			{
				strcat( &szPath[0], "/Fridge/Root" );
				break;
			}
			case FRIDGE_DIR_TEMPORARY_APP:
			{
				strcat( &szPath[0], "/Fridge/App" );
				break;
			}
			case FRIDGE_DIR_TEMPORARY_PRESET:
			{
				strcat( &szPath[0], "/Fridge/Preset" );
				break;
			}
			case FRIDGE_DIR_TEMPORARY_RESOURCES:
			{
				strcat( &szPath[0], "/Fridge/Resources" );
				break;
			}
		}
	}
	return &szPath[0];
}


// ___________________________________________________________________________________________

void FindInternal( SuperTree<FFileInfo>* pxFileList, const char* szPath, const char* szExtension, const bool bRecursive, const FHandle xParent )
{
	if( !pxFileList )
	{
		return;
	}

	char szFullString[MAX_PATH];
	strcpy_s( szFullString, szPath );
	strcat_s( szFullString, "*.*" );

	_finddata_t xFindData;
	intptr_t xFilePtr;

	xFilePtr = _findfirst( szFullString, &xFindData );

	if( xFilePtr == -1L )
	{
		return;
	}

	do
	{
		if( xFindData.name[0] == '.' )
		{
			// we always get back "." and ".."
			continue;
		}

		if( xFindData.attrib & _A_SUBDIR )
		{
			if( bRecursive )
			{
				char szSubPath[ MAX_PATH ];
				strcpy_s( szSubPath, szPath );
				sprintf_s( szSubPath, "%s%s/", szPath, xFindData.name );

				const FHandle xNewDirectoryHandle = pxFileList->Add( new FFileInfo( szSubPath, true ) );
				FindInternal( pxFileList, szSubPath, szExtension, true, xNewDirectoryHandle );
			}
		}
		else
		{
			const u_int uExtensionLength = strlen( szExtension );
			const u_int uNameLength = strlen( xFindData.name );
			const bool bHasExtension = !_stricmp( &( xFindData.name[ uNameLength - uExtensionLength ] ), szExtension );
			if( bHasExtension )
			{
				char szFull[ MAX_PATH ];
				sprintf_s( szFull, "%s%s", szPath, xFindData.name );
				pxFileList->Add( new FFileInfo( szFull, false ), xParent );
			}
		}
	}
	while ( _findnext( xFilePtr, &xFindData ) == 0 );
}

const char* GetFilterForType( FRIDGE_FILE_TYPES eType )
{
	static const char* aszFilter[] = {
										"Fridge Presets\0*.fridge\0",      // FRIDGE_FILE_PRESET
										"Fridge Templates\0*.template\0",  // FRIDGE_FILE_TEMPLATE
									 };

	return aszFilter[ eType ];
}

const char* GetExtensionForType( FRIDGE_FILE_TYPES eType )
{
	static const char* aszExtensions[] = {
											"fridge",    // FRIDGE_FILE_PRESET
											"template",  // FRIDGE_FILE_TEMPLATE
										 };

	return aszExtensions[ eType ];
}

const char* GetDirectoryForType( FRIDGE_FILE_TYPES eType )
{
	// TODO: At some point we need to prepend the User directory to this rather than using the directory where fridge is installed

	static const char* aszDirectory[] =  {
											"Presets",    // FRIDGE_FILE_PRESET
											"Templates",  // FRIDGE_FILE_TEMPLATE
										 };

	return aszDirectory[ eType ];
}

//eof
